package springfox.documentation.swagger.readers.parameter;

import com.fasterxml.classmate.ResolvedType;
import io.swagger.annotations.ApiParam;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.RequestParam;
import springfox.documentation.BeanUtils;
import springfox.documentation.schema.Collections;
import springfox.documentation.schema.Enums;
import springfox.documentation.schema.Example;
import springfox.documentation.service.AllowableValues;
import springfox.documentation.spi.schema.EnumTypeDeterminer;
import springfox.documentation.spi.service.contexts.ParameterContext;
import springfox.documentation.spring.web.DescriptionResolver;
import springfox.documentation.swagger.readers.parameter.ApiParamParameterBuilder;
import springfox.documentation.swagger.schema.ApiModelProperties;

import java.util.Optional;
import java.util.function.Predicate;

import static java.util.Optional.ofNullable;
import static org.springframework.util.StringUtils.isEmpty;
import static springfox.documentation.swagger.common.SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER;
import static springfox.documentation.swagger.readers.parameter.Examples.examples;

@Order(SWAGGER_PLUGIN_ORDER)
public class ApiParamParameterBuilderNew extends ApiParamParameterBuilder {
    private final DescriptionResolver descriptions;
    private final EnumTypeDeterminer enumTypeDeterminer;

    public ApiParamParameterBuilderNew(
            DescriptionResolver descriptions,
            EnumTypeDeterminer enumTypeDeterminer) {
        super(descriptions, enumTypeDeterminer);
        this.descriptions = descriptions;
        this.enumTypeDeterminer = enumTypeDeterminer;
    }

    @Override
    public void apply(ParameterContext context) {
        Optional<ApiParam> apiParam = context.resolvedMethodParameter().findAnnotation(ApiParam.class);
        context.parameterBuilder()
                .allowableValues(allowableValues(
                        context.alternateFor(context.resolvedMethodParameter().getParameterType()),
                        apiParam.map(ApiParam::allowableValues).orElse("")));
        if (apiParam.isPresent()) {
            ApiParam annotation = apiParam.get();
            context.parameterBuilder().name(ofNullable(annotation.name())
                            .filter(((Predicate<String>) String::isEmpty).negate()).orElse(null))
                    .description(ofNullable(descriptions.resolve(annotation.value()))
                            .filter(((Predicate<String>) String::isEmpty).negate()).orElse(null))
                    .parameterAccess(ofNullable(annotation.access())
                            .filter(((Predicate<String>) String::isEmpty).negate())
                            .orElse(null))
                    .defaultValue(ofNullable(annotation.defaultValue())
                            .filter(((Predicate<String>) String::isEmpty).negate())
                            .orElse(null))
                    .allowMultiple(annotation.allowMultiple())
                    .allowEmptyValue(annotation.allowEmptyValue())
//                    .required(annotation.required())
                    .scalarExample(new Example(annotation.example()))
                    .complexExamples(examples(annotation.examples()))
                    .hidden(annotation.hidden())
                    .collectionFormat(annotation.collectionFormat())
                    .order(SWAGGER_PLUGIN_ORDER);


            // 如果  required 已经被其他Plugin设置为true了则就不读取RequestParam的required
            boolean required = (Boolean) BeanUtils.getFieldValue(context.parameterBuilder(), "required");

            if (required) {
                return;
            }
            Optional<RequestParam> requestParam = context.resolvedMethodParameter().findAnnotation(RequestParam.class);

            if (requestParam.isPresent()) {
                context.parameterBuilder().required(requestParam.get().required());
            } else {
                context.parameterBuilder().required(annotation.required());
            }


        }
    }

    private AllowableValues allowableValues(ResolvedType parameterType, String allowableValueString) {
        AllowableValues allowableValues = null;
        if (!isEmpty(allowableValueString)) {
            allowableValues = ApiModelProperties.allowableValueFromString(allowableValueString);
        } else {
            if (enumTypeDeterminer.isEnum(parameterType.getErasedType())) {
                allowableValues = Enums.allowableValues(parameterType.getErasedType());
            }
            if (Collections.isContainerType(parameterType)) {
                allowableValues = Enums.allowableValues(Collections.collectionElementType(parameterType).getErasedType());
            }
        }
        return allowableValues;
    }



}
